﻿//----------------------------------------------------------------------------------------------------------------------
// <copyright file="ObservableCollectionEx.cs" company="Keith B. Rimington">
//
//   Copyright (c) 2011 Keith B. Rimington
//
//   Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
//     documentation files (the "Software"), to deal in the Software without restriction, including without limitation
//     the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
//     to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
//   The above copyright notice and this permission notice shall be included in all copies or substantial portions of
//     the Software.
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//     THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
//     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//     DEALINGS IN THE SOFTWARE.
//
// </copyright>
//----------------------------------------------------------------------------------------------------------------------

namespace Noc.Pomodoro.Core
{
    using System;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Linq;

    /// <summary>
    /// An extended observable collection that provides additional change notification for individual
    /// item property changes
    /// </summary>
    /// <typeparam name="TValue">The type of the collection values.</typeparam>
    public class ObservableCollectionEx<TValue> : ObservableCollection<TValue> where TValue : INotifyPropertyChanged
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ObservableCollectionEx&lt;TValue&gt;"/> class.
        /// </summary>
        public ObservableCollectionEx()
            : base()
        {
            this.CollectionChanged += new NotifyCollectionChangedEventHandler(this.OnCollectionChanged);
        }

        /// <summary>
        /// Occurs when an individual item property changes.
        /// </summary>
        public event PropertyChangedEventHandler ItemPropertyChanged;

        /// <summary>
        /// Removes all values matchint the specified prediate.
        /// </summary>
        /// <param name="predicate">The predicate.</param>
        public void RemoveAll(Func<TValue, bool> predicate)
        {
            var all = this.Where(predicate).ToArray();
            foreach (var single in all)
            {
                this.Remove(single);
            }
        }

        /// <summary>
        /// Called when the contents of the collection change, to connect/disconnect property change notifications.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs"/> instance containing the event data.</param>
        private void OnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.OldItems != null)
            {
                foreach (TValue item in e.OldItems)
                {
                    item.PropertyChanged -= this.OnItemPropertyChanged;
                }
            }

            if (e.NewItems != null)
            {
                foreach (TValue item in e.NewItems)
                {
                    item.PropertyChanged += this.OnItemPropertyChanged;
                }
            }
        }

        /// <summary>
        /// Called when an item property changes. Forwards the event notification to the <c>ItemPropertyChanged</c> event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
        private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (this.ItemPropertyChanged != null)
            {
                this.ItemPropertyChanged(sender, e);
            }
        }
    }
}